/* Created July 23, 2006.
 * Copyright (c) 2006, George Wright (geo@loyola.edu)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice, 
 *       this list of conditions and the following disclaimer.
 * 
 *     * Redistributions in binary form must reproduce the above copyright 
 *       notice, this list of conditions and the following disclaimer in the 
 *       documentation and/or other materials provided with the distribution.
 * 
 *     * Neither the name of George Wright nor the name of Loyola College
 *       may be used to endorse or promote products derived from this software 
 *       without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * To learn more about open source licenses, please visit: 
 * http://opensource.org/index.php
 * 
 * Changed by Vladimir Iglovikov
 */
package common;

import java.util.Arrays;

/**
 * Encapsulates a differencing operation on a series.
 * <p>
 * $Id: Difference.java,v 1.1 2008/07/02 12:48:56 Geo Exp $
 * </p>
 */
public class Difference {
	/**
	 * The initial value of the differenced originalSeries. Retained so the
	 * original series can be re-obtained.
	 */
	private double[] initialValue = null;

	/**
	 * The value of the differences.
	 */
	private double[] value = null;

	/**
	 * Default constructor.
	 */
	public Difference() {
		super();
		initialValue = null;
		value = null;
	}

	/**
	 * Copy constructor.
	 * 
	 * @param newDifference
	 */
	public Difference(Difference newDifference) {
		super();
		setInitialValue(newDifference == null ? null
				: newDifference.initialValue);
		setValue(newDifference == null ? null : newDifference.value);
	}

	/**
	 * Constructor with arguments. Takes the difference of the second argument,
	 * with period of the first argument, storing the intial value(s) prior to
	 * differencing so the original originalSeries can be reconstituted.
	 * 
	 * @param period
	 *            The period of the differencing operation.
	 * @param seriesValue
	 *            The values to difference.
	 */
	public Difference(int period, double[] seriesValue) {
		try {
			if (period < 1 || period > Constants.MAX_DIFFERENCE_ORDER)
				throw new ForecastException(
						Constants.STRINGS.getString("Differencing.message1")
								+ period
								+ Constants.STRINGS
										.getString("Differencing.message2")
								+ " " + Constants.MAX_DIFFERENCE_ORDER);
		} catch (ForecastException ae) {
			ForecastException.handleException(ae);
		}
		int seriesLength = seriesValue.length;
		initialValue = new double[period];
		for (int i = 0; i < period; i++)
			initialValue[i] = seriesValue[i];
		value = new double[seriesLength - period];
		for (int i = period; i < seriesLength; i++)
			value[i - period] = seriesValue[i] - seriesValue[i - period];
	}

	/**
	 * Compares two objects for equality. Returns a boolean that indicates
	 * whether this object is equivalent to the specified object.
	 * 
	 * @param obj
	 *            the Object to compare with
	 * @return true if these Objects are equal; false otherwise.
	 */
	public boolean equals(Object obj) {
		if (obj == null)
			return false;
		if (!(obj instanceof Difference))
			return false;
		Difference differenceObject = new Difference((Difference) obj);
		if (!(Arrays.equals(this.initialValue, differenceObject.initialValue)))
			return false;
		if (!(Arrays.equals(this.value, differenceObject.value)))
			return false;
		return true;
	}

	/**
	 * Gets initialValue.
	 * 
	 * @return Returns the initialValue.
	 */
	public double[] getInitialValue() {
		return initialValue;
	}

	/**
	 * Gets value.
	 * 
	 * @return Returns the value.
	 */
	public double[] getValue() {
		return value;
	}

	/**
	 * Sets the initialValue.
	 * 
	 * @param newInitialValue
	 *            The initialValue to set.
	 */
	public void setInitialValue(double[] newInitialValue) {
		if (newInitialValue == null)
			initialValue = null;
		else {
			int length = newInitialValue.length;
			initialValue = new double[length];
			for (int i = 0; i < length; i++)
				initialValue[i] = newInitialValue[i];
		}
	}

	/**
	 * Sets the value.
	 * 
	 * @param newValue
	 *            The value to set.
	 */
	public void setValue(double[] newValue) {
		if (newValue == null)
			value = null;
		else {
			int length = newValue.length;
			value = new double[length];
			for (int i = 0; i < length; i++)
				value[i] = newValue[i];
		}
	}

	/**
	 * Prepares the difference for dump at the terminal.
	 * 
	 * @return The <code>String</code> representation of the
	 *         <code>Forecast</code> instance.
	 */
	@Override
	public String toString() {
		String result = "";
		if (initialValue == null || value == null)
			result += "No differenced values set\n";
		else {
			result += "Initial values:\n";
			for (int i = 0; i < initialValue.length; i++)
				result += (initialValue[i] + "\n");
			result += "Differenced values:\n";
			for (int i = 0; i < value.length; i++)
				result += (value[i] + "\n");
		}
		return result;
	}
}
